﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using VMLua;
using LPMEDTranslator.Model;
using LPMEDDebugger.Model;
using Descriptions_DomainModel.Model;
using TestImplementations.Model;
using CommonClasses.Model;
using CommonClasses.Services;
using System.Reflection;
using System.Threading;
using System.Collections;
using LPMEDInterpreter.Model;
using IDE;
using DomainModelEditor;
using Descriptions_DomainModelLoader;

namespace RunTimeTests
{
    /* Логика работы такова:
     * 1) каждый из методов, помеченных атрибутом TestMethod, выполняется
     * 2) в течение TactLimit тактов ожиадется результат в виде вызова Handler (он должен быть подписан на соответствующее событие)
     * 3) если ответ пришел, то тест пройден
     */
    public partial class Form1 : Form
    {        
        DomainModel _DomainModel;
        IDEEcoSpace _TestEcoSpace;
        TestLPMEDModule _testModule;
        TestLPMEDTextPoint _testBreakP1;
        TestLPMEDVariable _testVar1;
        TestCodeEditor _testEditor;
        TestInterpretationBlock _testBlock1;
        TestInterpretationBlock _testBlock2;
        TestInterpretationBlock _testBlock3;
        CommonClasses.Logger.ILoggingManagement main_log = null;
        CommonClasses.Logger.ILogger _log = null;
        int RequestCount = 0;
        int TactNum = 0;
        const int TactLimit = 1;

        public Form1()
        {
            InitializeComponent();

            AllInitialize();

            var currenttest = "VMLua";

            Type testformtype = this.GetType();

            //Выбираем только тесты
            IEnumerable<MethodInfo> mets = from met in testformtype.GetMethods()
                where (met.GetCustomAttributes(typeof(TestMethodAttribute), false).Length == 1)                
                select met;


            foreach (MethodInfo inf in mets)
            {
                TestInitialize(); //Подготовиться к тесту

                if ((inf.GetCustomAttributes(typeof(TestMethodAttribute), false)[0] as TestMethodAttribute).Module != currenttest)
                {
                    TestCleanup(); //чистим
                    continue;
                }

                inf.Invoke(this, new object[0]); //выполняем тест               

                for (int i = 0; i < TactLimit; i++)
                {
                    ProcessTact();
                    if (RequestCount == 0)
                        break;
                }
                TestCleanup(); //чистим
                AddTest(inf); //Добавить в тесты
                if (RequestCount == 0)
                    AddDone(inf); //Добавить в выполненные тесты
            }                       
        }

        private void AddTest(MethodInfo met)
        {            
            this.listBox1.Items.Add(
                met.GetCustomAttributes(typeof(TestMethodAttribute), false)[0]                    
                    .ToString() +
                met.Name);
        }

        private void AddDone(MethodInfo met)
        {
            this.listBox2.Items.Add(
                met.GetCustomAttributes(typeof(TestMethodAttribute), false)[0]
                    .ToString() +
                met.Name);
        }

        public void AllInitialize()
        {
           // MCSharp.Session.Init();
            main_log = CommonClasses.Logger.LoggerManager.CreateOnce("..\\..\\..\\LoggerManager.ih.config", ".\\logs");

            _TestEcoSpace = new IDEEcoSpace(main_log.GetLogger("IDELogger"));
            _TestEcoSpace.Active = true;

            var loader = new DomainModelsLoader(_TestEcoSpace);
            loader.LoadDeviceDescriptionsFromMainFile(@"C:\0_MyFiles\programming\Projects\CSharp 3\IronHand\Ver.3\CurrentVersion\IDE\IDEMainForm\bin\Debug\Типовые описания оборудования\CAST2\CAST2DM.main.ihdm");
            _DomainModel = _TestEcoSpace.Ocl.Evaluate("DomainModel.allInstances->first").AsObject as DomainModel;

            RequestCount = 0;
            TactNum = 0;
        }

        public void TestInitialize()
        {
            RequestCount = 0;
            _testModule = new TestLPMEDModule(_TestEcoSpace);                        
            _testEditor = new TestCodeEditor(_TestEcoSpace);
            _testBlock1 = new TestInterpretationBlock(_TestEcoSpace);
            _testBlock2 = new TestInterpretationBlock(_TestEcoSpace);
            _testBlock3 = new TestInterpretationBlock(_TestEcoSpace);

            _testModule.OnVariableChanged += new VariableStateChangedHandler(VariableChangeHandler);
            _testModule.OnBreakpoint += new BreakpointFiredHandler(BreakpointHandler);

            #region Interpretation blocks signature
            _testBlock1.OnCompilationFailed += new CompilationFailedHandler(_testBlock_OnCompilationFailed);
            _testBlock1.OnInterpretationFinished += new MethodInvoker(_testBlock_OnInterpretationFinished);
            _testBlock1.OnInterpretationStarted += new MethodInvoker(_testBlock_OnInterpretationStarted);
            _testBlock1.OnRunTimeErrorOccured += new RunTimeErrorOccuredHandler(_testBlock_OnRunTimeErrorOccured);
            _testBlock2.OnCompilationFailed += new CompilationFailedHandler(_testBlock_OnCompilationFailed);
            _testBlock2.OnInterpretationFinished += new MethodInvoker(_testBlock_OnInterpretationFinished);
            _testBlock2.OnInterpretationStarted += new MethodInvoker(_testBlock_OnInterpretationStarted);
            _testBlock2.OnRunTimeErrorOccured += new RunTimeErrorOccuredHandler(_testBlock_OnRunTimeErrorOccured);
            _testBlock3.OnCompilationFailed += new CompilationFailedHandler(_testBlock_OnCompilationFailed);
            _testBlock3.OnInterpretationFinished += new MethodInvoker(_testBlock_OnInterpretationFinished);
            _testBlock3.OnInterpretationStarted += new MethodInvoker(_testBlock_OnInterpretationStarted);
            _testBlock3.OnRunTimeErrorOccured += new RunTimeErrorOccuredHandler(_testBlock_OnRunTimeErrorOccured); 
            #endregion

            _TestEcoSpace
                .GetEcoService<IVirtualMachineService>()
                .OnTerminateAll += new MethodInvoker(Form1_OnTerminateAll);

            _TestEcoSpace.GetEcoService<IDebuggerService>().NewDebugSession();
        }

        public void TestCleanup()
        {
            _testModule.OnVariableChanged -= new VariableStateChangedHandler(VariableChangeHandler);
            _testModule.OnBreakpoint -= new BreakpointFiredHandler(BreakpointHandler);

            #region Interpretation blocks signature
            _testBlock1.OnCompilationFailed -= new CompilationFailedHandler(_testBlock_OnCompilationFailed);
            _testBlock1.OnInterpretationFinished -= new MethodInvoker(_testBlock_OnInterpretationFinished);
            _testBlock1.OnInterpretationStarted -= new MethodInvoker(_testBlock_OnInterpretationStarted);
            _testBlock1.OnRunTimeErrorOccured -= new RunTimeErrorOccuredHandler(_testBlock_OnRunTimeErrorOccured);
            _testBlock2.OnCompilationFailed -= new CompilationFailedHandler(_testBlock_OnCompilationFailed);
            _testBlock2.OnInterpretationFinished -= new MethodInvoker(_testBlock_OnInterpretationFinished);
            _testBlock2.OnInterpretationStarted -= new MethodInvoker(_testBlock_OnInterpretationStarted);
            _testBlock2.OnRunTimeErrorOccured -= new RunTimeErrorOccuredHandler(_testBlock_OnRunTimeErrorOccured);
            _testBlock3.OnCompilationFailed -= new CompilationFailedHandler(_testBlock_OnCompilationFailed);
            _testBlock3.OnInterpretationFinished -= new MethodInvoker(_testBlock_OnInterpretationFinished);
            _testBlock3.OnInterpretationStarted -= new MethodInvoker(_testBlock_OnInterpretationStarted);
            _testBlock3.OnRunTimeErrorOccured -= new RunTimeErrorOccuredHandler(_testBlock_OnRunTimeErrorOccured);
            #endregion

            _TestEcoSpace
                .GetEcoService<IVirtualMachineService>()
                .OnTerminateAll -= new MethodInvoker(Form1_OnTerminateAll);
        }        

        public void AllCleanup()
        {
            main_log.Dispose();
           // MCSharp.Session.FinalizeIt();
        }

        void ProcessTact()
        {
            TactNum++;
            _TestEcoSpace.GetEcoService<IVirtualMachineService>().ProcessOneStep();
        }        
        /// <summary>
        /// В отладчик посылается программа с одной точкой останова и выполняется
        /// </summary>
        [TestMethod("Debugger")]
        public void DebTest1()
        {
            RequestCount = 1;
            _testModule.LPMEDCode = @"
            DEVICE testdev1
            VAR V1: int;
            V2: float;
            {
                V1 = 1;                
                V1 = 5;               
            }
            END.";

            _testBreakP1 = new TestLPMEDTextPoint(_TestEcoSpace);
            _testBreakP1.LineNumber = 6;
            _testBreakP1.CharNumber = 0;
            _testModule.Breakpoints.Add(_testBreakP1);

            _TestEcoSpace.GetEcoService<IDebuggerService>().CommitProgram(_testModule);
        }
        /// <summary>
        /// В отладчик посылается программа с одной Watch и выполняется
        /// </summary>
        [TestMethod("Debugger")]
        public void Test2()
        {
            RequestCount = 1;
            _testModule.LPMEDCode = @"
            DEVICE testdev1
            VAR V1: int;
            V2: float;
            {
                V1 = 1;                
                V1 = 5 + 1;  
                V2 = V1 + V1;
                V1 = V2 + V1;
            }
            END.";

            _testVar1 = new TestLPMEDVariable(_TestEcoSpace);
            
            _testVar1.Name = "V1";
            _testVar1.Type = "int";

            _testModule.Watches.Add(_testVar1);

            _TestEcoSpace.GetEcoService<IDebuggerService>().CommitProgram(_testModule);
        }

        /// <summary>
        /// Выполняется 3 блока интерпретации. Только работа с переменными
        /// </summary>
        [TestMethod("Interpreter")]
        public void InterTest1()
        {
            RequestCount = 3;
            _testBlock1.Code = @"
                VAR V1, V2: int;
                V1 = 1;
                V1 = 5 + 1;
                V2 = V1 + V1;
                V1 = V2 + V1;";           

            _TestEcoSpace.GetEcoService<IInterpreterService>()
                .DoBlock(_testBlock1);

            _testBlock2.Code = @"                
                V1 = 2;
                V1 = 5 + 1;
                V2 = V1 + V1;
                V1 = V2 + V1;";

            _TestEcoSpace.GetEcoService<IInterpreterService>()
                .DoBlock(_testBlock2);

            _testBlock3.Code = @"                
                V1 = 3;
                V1 = 5 + 1;
                V2 = V1 + V1;
                V1 = V2 + V1;";

            _TestEcoSpace.GetEcoService<IInterpreterService>()
                .DoBlock(_testBlock3);
        }

        /// <summary>
        /// Выполняется команда terminate_all
        /// </summary>
        [TestMethod("VMLua")]
        public void TerminateTest1()
        {
            RequestCount = 1;
            string LPMEDCode = @"
            DEVICE Mp11
            {
                terminate_all;
            }
            END.";
            var CompData = new CompilationData(_TestEcoSpace);

            //синтаксис
            object tree = null;
            ErrorReport er = _TestEcoSpace.GetEcoService<ITranslatorService>().SyntaxCheck(
                LPMEDCode,
                new cLPMEDFirstStageGrammar(_TestEcoSpace),
                new List<IASTTransformer> { },
                out tree);

            //семантика
            er = _TestEcoSpace.GetEcoService<ITranslatorService>().SemanticCheck(tree);

            CompData.Tree.Object = tree;

            //компиляция
            _TestEcoSpace.GetEcoService<ITranslatorService>().Translate(
                ref CompData);

            var actor = new ActiveObject("Mp11");
            actor.LuaProgram = CompData.CompiledCode;
            actor.ScriptOneStepCode = CompData.CoroutineCallString;

            _TestEcoSpace.GetEcoService<IVirtualMachineService>()
                .RegisterActiveObject(actor);
        }

        #region Debugger event handlers
        void VariableChangeHandler(ILPMEDVariable var)
        {
            RequestCount--;
        }

        void BreakpointHandler(ILPMEDTextPoint point)
        {
            RequestCount--;
        } 
        #endregion

        #region Interpreter event handler
        void _testBlock_OnRunTimeErrorOccured(string message)
        {
            //Failed = false;
        }

        void _testBlock_OnInterpretationStarted()
        {
            //Failed = false;
        }

        void _testBlock_OnInterpretationFinished()
        {
            RequestCount--;
        }

        void _testBlock_OnCompilationFailed(ErrorReport report)
        {
            //Failed = false;
        }
        #endregion

        #region VMLua Event Handlers
        void Form1_OnTerminateAll()
        {
            RequestCount--;
        } 
        #endregion

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            AllCleanup();
        }
    }

    sealed class TestMethodAttribute : Attribute
    {
        public string Module { get; private set; }
        public TestMethodAttribute(string module)
        {
            this.Module = module;
        }
        public override string ToString()
        {
            return "TestMethod: " + Module + " ";
        }
    }

}
